package blackstar.agent.web;

import java.io.File;
import java.io.IOException;
import java.util.Map;

import javax.management.remote.JMXServiceURL;

import mx4j.tools.remote.http.WebContainer;
import mx4j.tools.remote.http.jetty.JettyWebContainer;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mortbay.jetty.Connector;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.bio.SocketConnector;
import org.mortbay.jetty.security.SecurityHandler;
import org.mortbay.jetty.servlet.Context;
import org.mortbay.jetty.webapp.WebAppContext;

import blackstar.agent.AgentConfig;
import blackstar.agent.event.AfterStartupEvent;
import blackstar.agent.event.Event;
import blackstar.agent.event.EventListener;
import blackstar.agent.event.StartupEvent;

/**
 * @author RayWoo (ayufox@gmail.com)
 * 
 */
public class JettyWebService extends JettyWebContainer implements
		EventListener, WebContainer
{
	private final static Log LOGGER = LogFactory.getLog(JettyWebService.class);

	private final Server server = new Server();

	private Context rootContext = new Context();
	{
		rootContext.setContextPath("/");
		rootContext.setClassLoader(JettyWebService.class.getClassLoader());
		SecurityHandler securityHandler = JettySecurityUtil
				.createSecurityHandler("root");
		if (securityHandler != null)
		{
			rootContext.setSecurityHandler(securityHandler);
		}
		deployServlet(IndexServlet.class.getName(), "/");
	}

	public JettyWebService()
	{
		LOGGER.info("=======================Instance");
	}

	public void startup() throws Exception
	{
		AgentWebContainer.setInstance(this);

		String ip = AgentConfig.getWebIP();
		int port = AgentConfig.getWebPort();
		Connector connector = new SocketConnector();
		if (ip != null && ip.trim().length() > 0)
		{
			connector.setHost(ip.trim());
		}
		connector.setPort(port);
		this.server.addConnector(connector);

		LOGGER.info("============Startup");
	}

	public void afterStartup() throws Exception
	{
		server.addHandler(rootContext);

		this.server.start();

		LOGGER.info("============Jetty Startup");
	}

	public void start(JMXServiceURL url, Map environment) throws IOException
	{
		LOGGER.info("start [" + url + "]");
	}

	public void stop() throws IOException
	{
		try
		{
			this.server.stop();
		} catch (Exception e)
		{
			LOGGER.error("error when stop JettyServer", e);
		}
	}

	public void deploy(String servletClassName, JMXServiceURL url,
			Map environment) throws IOException
	{
		String urlPattern = resolveServletMapping(url);
		deployServlet(servletClassName, urlPattern);
	}

	public void deployServlet(String servletClassName, String urlPattern)
	{
		this.rootContext.addServlet(servletClassName, urlPattern);
		LOGGER.info("============addServlet[servlet=" + servletClassName
				+ ",urlPattern=" + urlPattern + "]");
	}

	public void undeploy(String servletName, JMXServiceURL url, Map environment)
	{
		String urlPattern = resolveServletMapping(url);

		LOGGER.info("undeploy[servletName=" + servletName + ",urlPattern="
				+ urlPattern + "]");
	}

	private String resolveServletMapping(JMXServiceURL url)
	{
		String path = url.getURLPath();
		String urlPattern = null;
		if (path.endsWith("/"))
			urlPattern = path + "*";
		else
			urlPattern = path + "/*";
		if (!urlPattern.startsWith("/"))
			urlPattern = "/" + urlPattern;
		return urlPattern;
	}

	public void deploy(String webApp, String contextPath)
	{
		LOGGER.info("============Deploy[webApp=" + webApp + ",contextPath="
				+ contextPath + "]");
		WebAppContext wac = new WebAppContext();
		wac.setContextPath(contextPath);
		wac.setWar(webApp);
		wac.setTempDirectory(new File(AgentConfig.getWebTempPath()
				+ File.separator + contextPath));

		String securityContext = contextPath.substring(1);
		SecurityHandler securityHandler = JettySecurityUtil
				.createSecurityHandler(securityContext);
		if (securityHandler != null)
		{
			wac.setSecurityHandler(securityHandler);
		}
		server.addHandler(wac);
	}

	public Class[] events()
	{
		return new Class[]
		{ StartupEvent.class, AfterStartupEvent.class, DeployWarEvent.class,
				DeployServletEvent.class };
	}

	public void onEvent(Event event) throws Exception
	{
		if (event instanceof StartupEvent)
		{
			startup();
		} else if (event instanceof AfterStartupEvent)
		{
			afterStartup();
		} else if (event instanceof DeployWarEvent)
		{
			DeployWarEvent dwse = (DeployWarEvent) event;
			deploy(dwse.getWebApp(), dwse.getContextPath());
		} else if (event instanceof DeployServletEvent)
		{
			DeployServletEvent dse = (DeployServletEvent) event;
			deployServlet(dse.getServletClass().getName(), dse.getUrlPattern());
		} else
		{
			LOGGER.warn("Unhandle event[" + event + "]");
		}
	}
}
